/*
* Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of Flamingo Kirill Grouchnikov nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.pushingpixels.flamingo.internal.ui.ribbon;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.*;
import org.pushingpixels.flamingo.api.common.*;
import org.pushingpixels.flamingo.api.common.icon.ResizableIcon;
import org.pushingpixels.flamingo.api.common.popup.*;
import org.pushingpixels.flamingo.api.ribbon.*;
import org.pushingpixels.flamingo.api.ribbon.resize.IconRibbonBandResizePolicy;
import org.pushingpixels.flamingo.api.ribbon.resize.RibbonBandResizePolicy;
import org.pushingpixels.flamingo.internal.ui.common.BasicCommandButtonUI;
import org.pushingpixels.flamingo.internal.utils.FlamingoUtilities;
import org.pushingpixels.flamingo.internal.utils.RenderingUtils;
import org.pushingpixels.trident.Timeline;
import org.pushingpixels.trident.swing.SwingRepaintCallback;
/**
* Basic UI for ribbon band {@link JRibbonBand}.
*
* @author Kirill Grouchnikov
* @author Matt Nathan
*/
public class BasicRibbonBandUI extends RibbonBandUI {
/**
* The associated ribbon band.
*/
protected AbstractRibbonBand ribbonBand;
/**
* The button for collapsed state.
*/
protected JCommandButton collapsedButton;
/**
* The band expand button. Is visible when the
* {@link JRibbonBand#getExpandActionListener()} of the associated ribbon
* band is not <code>null</code>.
*/
protected AbstractCommandButton expandButton;
protected float rolloverAmount;
protected Timeline rolloverTimeline;
/**
* Mouse listener on the associated ribbon band.
*/
protected MouseListener mouseListener;
/**
* Listens to property changes on the associated ribbon band.
*/
protected PropertyChangeListener propertyChangeListener;
/**
* Action listener on the expand button.
*/
protected ActionListener expandButtonActionListener;
/**
* Popup panel that shows the contents of the ribbon band when it is in a
* collapsed state.
*
* @author Kirill Grouchnikov
*/
protected static class CollapsedButtonPopupPanel extends JPopupPanel {
/**
* The main component of <code>this</code> popup panel. Can be
* <code>null</code>.
*/
protected Component component;
/**
* Creates popup gallery with the specified component.
*
* @param component
* The main component of the popup gallery.
* @param originalSize
* The original dimension of the main component.
*/
public CollapsedButtonPopupPanel(Component component,
Dimension originalSize) {
this.component = component;
this.setLayout(new BorderLayout());
this.add(component, BorderLayout.CENTER);
// System.out.println("Popup dim is " + originalSize);
this.setPreferredSize(originalSize);
this.setSize(originalSize);
}
/**
* Removes the main component of <code>this</code> popup gallery.
*
* @return The removed main component.
*/
public Component removeComponent() {
this.remove(this.component);
return this.component;
}
/**
* Returns the main component of <code>this</code> popup gallery.
*
* @return The main component.
*/
public Component getComponent() {
return this.component;
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
*/
public static ComponentUI createUI(JComponent c) {
return new BasicRibbonBandUI();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#installUI(javax.swing.JComponent)
*/
@Override
public void installUI(JComponent c) {
this.ribbonBand = (AbstractRibbonBand) c;
this.rolloverTimeline = new Timeline(this);
this.rolloverTimeline.addPropertyToInterpolate("rolloverAmount", 0.0f,
1.0f);
this.rolloverTimeline.addCallback(new SwingRepaintCallback(
this.ribbonBand));
this.rolloverTimeline.setDuration(250);
installDefaults();
installComponents();
installListeners();
c.setLayout(createLayoutManager());
AWTRibbonEventListener.install();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#uninstallUI(javax.swing.JComponent)
*/
@Override
public void uninstallUI(JComponent c) {
c.setLayout(null);
uninstallListeners();
uninstallDefaults();
uninstallComponents();
if (!AWTRibbonEventListener.uninstall()) {
// should remove other methods of tracking
}
}
/**
* Installs default parameters on the associated ribbon band.
*/
protected void installDefaults() {
Color bg = this.ribbonBand.getBackground();
if (bg == null || bg instanceof UIResource) {
this.ribbonBand.setBackground(FlamingoUtilities.getColor(
Color.lightGray, "RibbonBand.background",
"Panel.background"));
}
Border b = this.ribbonBand.getBorder();
if (b == null || b instanceof UIResource) {
Border toSet = UIManager.getBorder("RibbonBand.border");
if (toSet == null)
toSet = new BorderUIResource(new RoundBorder(FlamingoUtilities
.getBorderColor(), new Insets(2, 2, 2, 2)));
this.ribbonBand.setBorder(toSet);
}
}
/**
* Installs subcomponents on the associated ribbon band.
*/
protected void installComponents() {
this.collapsedButton = new JCommandButton(this.ribbonBand.getTitle(),
this.ribbonBand.getIcon());
this.collapsedButton.setDisplayState(CommandButtonDisplayState.BIG);
this.collapsedButton
.setCommandButtonKind(JCommandButton.CommandButtonKind.POPUP_ONLY);
this.collapsedButton.setPopupKeyTip(this.ribbonBand
.getCollapsedStateKeyTip());
this.ribbonBand.add(this.collapsedButton);
if (this.ribbonBand.getExpandActionListener() != null) {
this.expandButton = this.createExpandButton();
this.ribbonBand.add(this.expandButton);
}
}
/**
* Creates the expand button for the associated ribbon band.
*
* @return Expand button for the associated ribbon band.
*/
protected JCommandButton createExpandButton() {
ResizableIcon icon = FlamingoUtilities
.getRibbonBandExpandIcon(this.ribbonBand);
JCommandButton result = new JCommandButton(null, icon);
result.setFlat(true);
result.putClientProperty(BasicCommandButtonUI.EMULATE_SQUARE_BUTTON,
Boolean.TRUE);
result.setBorder(new EmptyBorder(3, 2, 3, 2));
result.setActionKeyTip(this.ribbonBand.getExpandButtonKeyTip());
result.setActionRichTooltip(this.ribbonBand
.getExpandButtonRichTooltip());
return result;
}
protected void syncExpandButtonIcon() {
this.expandButton.setIcon(FlamingoUtilities
.getRibbonBandExpandIcon(this.ribbonBand));
}
/**
* Installs listeners on the associated ribbon band.
*/
protected void installListeners() {
// without this empty adapter, the global listener never
// gets mouse entered events on the ribbon band
this.mouseListener = new MouseAdapter() {
};
this.ribbonBand.addMouseListener(this.mouseListener);
configureExpandButton();
this.propertyChangeListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("title".equals(evt.getPropertyName()))
ribbonBand.repaint();
if ("expandButtonKeyTip".equals(evt.getPropertyName())) {
if (expandButton != null) {
expandButton
.setActionKeyTip((String) evt.getNewValue());
}
}
if ("expandButtonRichTooltip".equals(evt.getPropertyName())) {
if (expandButton != null) {
expandButton.setActionRichTooltip((RichTooltip) evt
.getNewValue());
}
}
if ("collapsedStateKeyTip".equals(evt.getPropertyName())) {
if (collapsedButton != null) {
collapsedButton.setPopupKeyTip((String) evt
.getNewValue());
}
}
if ("expandActionListener".equals(evt.getPropertyName())) {
ActionListener oldListener = (ActionListener) evt
.getOldValue();
ActionListener newListener = (ActionListener) evt
.getNewValue();
if ((oldListener != null) && (newListener == null)) {
// need to remove
unconfigureExpandButton();
ribbonBand.remove(expandButton);
expandButton = null;
ribbonBand.revalidate();
}
if ((oldListener == null) && (newListener != null)) {
// need to add
expandButton = createExpandButton();
configureExpandButton();
ribbonBand.add(expandButton);
ribbonBand.revalidate();
}
if ((oldListener != null) && (newListener != null)) {
// need to reconfigure
expandButton.removeActionListener(oldListener);
expandButton.addActionListener(newListener);
}
}
if ("componentOrientation".equals(evt.getPropertyName())) {
if (expandButton != null) {
syncExpandButtonIcon();
}
}
}
};
this.ribbonBand.addPropertyChangeListener(this.propertyChangeListener);
}
protected void configureExpandButton() {
if (this.expandButton != null) {
this.expandButton.addActionListener(this.ribbonBand
.getExpandActionListener());
this.expandButtonActionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
trackMouseCrossing(false);
}
});
}
};
this.expandButton
.addActionListener(this.expandButtonActionListener);
}
}
/**
* Uninstalls default parameters from the associated ribbon band.
*/
protected void uninstallDefaults() {
LookAndFeel.uninstallBorder(this.ribbonBand);
}
/**
* Uninstalls components from the associated ribbon band.
*/
protected void uninstallComponents() {
if (this.collapsedButton.isVisible()) {
// restore the control panel to the ribbon band.
CollapsedButtonPopupPanel popupPanel = (collapsedButton
.getPopupCallback() == null) ? null
: (CollapsedButtonPopupPanel) collapsedButton
.getPopupCallback().getPopupPanel(collapsedButton);
if (popupPanel != null) {
AbstractRibbonBand bandFromPopup = (AbstractRibbonBand) popupPanel
.removeComponent();
ribbonBand.setControlPanel(bandFromPopup.getControlPanel());
ribbonBand.setPopupRibbonBand(null);
collapsedButton.setPopupCallback(null);
}
}
this.ribbonBand.remove(this.collapsedButton);
this.collapsedButton = null;
if (this.expandButton != null)
this.ribbonBand.remove(this.expandButton);
this.expandButton = null;
this.ribbonBand = null;
}
/**
* Uninstalls listeners from the associated ribbon band.
*/
protected void uninstallListeners() {
this.ribbonBand
.removePropertyChangeListener(this.propertyChangeListener);
this.propertyChangeListener = null;
this.ribbonBand.removeMouseListener(this.mouseListener);
this.mouseListener = null;
unconfigureExpandButton();
}
protected void unconfigureExpandButton() {
if (this.expandButton != null) {
this.expandButton
.removeActionListener(this.expandButtonActionListener);
this.expandButtonActionListener = null;
this.expandButton.removeActionListener(this.ribbonBand
.getExpandActionListener());
}
}
/**
* Invoked by <code>installUI</code> to create a layout manager object to
* manage the {@link JCommandButtonStrip}.
*
* @return a layout manager object
*/
protected LayoutManager createLayoutManager() {
return new RibbonBandLayout();
}
/**
* Layout for the ribbon band.
*
* @author Kirill Grouchnikov
*/
private class RibbonBandLayout implements LayoutManager {
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#addLayoutComponent(java.lang.String,
* java.awt.Component)
*/
public void addLayoutComponent(String name, Component c) {
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#removeLayoutComponent(java.awt.Component)
*/
public void removeLayoutComponent(Component c) {
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
*/
public Dimension preferredLayoutSize(Container c) {
Insets ins = c.getInsets();
AbstractBandControlPanel controlPanel = ribbonBand
.getControlPanel();
boolean useCollapsedButton = (controlPanel == null)
|| (!controlPanel.isVisible());
int width = useCollapsedButton ? collapsedButton.getPreferredSize().width
: controlPanel.getPreferredSize().width;
int height = (useCollapsedButton ? collapsedButton
.getPreferredSize().height : controlPanel
.getPreferredSize().height)
+ getBandTitleHeight();
// System.out.println(ribbonBand.getTitle() + ":" + height);
// Preferred height of the ribbon band is:
// 1. Insets on top and bottom
// 2. Preferred height of the control panel
// 3. Preferred height of the band title panel
// System.out.println("Ribbon band pref = "
// + (height + ins.top + ins.bottom));
return new Dimension(width + 2 + ins.left + ins.right, height
+ ins.top + ins.bottom);
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
*/
public Dimension minimumLayoutSize(Container c) {
Insets ins = c.getInsets();
AbstractBandControlPanel controlPanel = ribbonBand
.getControlPanel();
boolean useCollapsedButton = (controlPanel == null)
|| (!controlPanel.isVisible());
int width = useCollapsedButton ? collapsedButton.getMinimumSize().width
: controlPanel.getMinimumSize().width;
int height = useCollapsedButton ? collapsedButton.getMinimumSize().height
+ getBandTitleHeight()
: controlPanel.getMinimumSize().height
+ getBandTitleHeight();
// System.out.println(useCollapsedButton + ":" + height);
// Preferred height of the ribbon band is:
// 1. Insets on top and bottom
// 2. Preferred height of the control panel
// 3. Preferred height of the band title panel
return new Dimension(width + 2 + ins.left + ins.right, height
+ ins.top + ins.bottom);
}
/*
* (non-Javadoc)
*
* @see java.awt.LayoutManager#layoutContainer(java.awt.Container)
*/
public void layoutContainer(Container c) {
// System.out.println("Ribbon band real = " + c.getHeight());
if (!c.isVisible())
return;
Insets ins = c.getInsets();
int availableHeight = c.getHeight() - ins.top - ins.bottom;
RibbonBandResizePolicy resizePolicy = ((AbstractRibbonBand) c)
.getCurrentResizePolicy();
if (resizePolicy instanceof IconRibbonBandResizePolicy) {
collapsedButton.setVisible(true);
int w = collapsedButton.getPreferredSize().width;
// System.out.println("Width for collapsed of '"
// + ribbonBand.getTitle() + "' is " + w);
collapsedButton.setBounds((c.getWidth() - w) / 2, ins.top, w, c
.getHeight()
- ins.top - ins.bottom);
// System.out.println("Collapsed " + collapsedButton.getHeight()
// + ":" + c.getHeight());
if (collapsedButton.getPopupCallback() == null) {
final AbstractRibbonBand popupBand = ribbonBand.cloneBand();
popupBand.setControlPanel(ribbonBand.getControlPanel());
List<RibbonBandResizePolicy> resizePolicies = ribbonBand
.getResizePolicies();
popupBand.setResizePolicies(resizePolicies);
RibbonBandResizePolicy largest = resizePolicies.get(0);
popupBand.setCurrentResizePolicy(largest);
int gap = popupBand.getControlPanel().getUI()
.getLayoutGap();
final Dimension size = new Dimension(ins.left + ins.right
+ gap
+ largest.getPreferredWidth(availableHeight, gap),
ins.top
+ ins.bottom
+ Math.max(c.getHeight(), ribbonBand
.getControlPanel()
.getPreferredSize().height
+ getBandTitleHeight()));
// System.out.println(ribbonBand.getTitle() + ":"
// + size.getHeight());
collapsedButton.setPopupCallback(new PopupPanelCallback() {
@Override
public JPopupPanel getPopupPanel(
JCommandButton commandButton) {
return new CollapsedButtonPopupPanel(popupBand,
size);
}
});
// collapsedButton.setGallery(new JPopupGallery(ribbonBand
// .getControlPanel(), size));
ribbonBand.setControlPanel(null);
ribbonBand.setPopupRibbonBand(popupBand);
}
if (expandButton != null)
expandButton.setBounds(0, 0, 0, 0);
return;
}
if (collapsedButton.isVisible()) {
// was icon and now is normal band - have to restore the
// control panel
CollapsedButtonPopupPanel popupPanel = (collapsedButton
.getPopupCallback() != null) ? (CollapsedButtonPopupPanel) collapsedButton
.getPopupCallback().getPopupPanel(collapsedButton)
: null;
if (popupPanel != null) {
AbstractRibbonBand bandFromPopup = (AbstractRibbonBand) popupPanel
.removeComponent();
ribbonBand.setControlPanel(bandFromPopup.getControlPanel());
ribbonBand.setPopupRibbonBand(null);
collapsedButton.setPopupCallback(null);
}
}
collapsedButton.setVisible(false);
AbstractBandControlPanel controlPanel = ribbonBand
.getControlPanel();
controlPanel.setVisible(true);
controlPanel.setBounds(ins.left, ins.top, c.getWidth() - ins.left
- ins.right, c.getHeight() - getBandTitleHeight() - ins.top
- ins.bottom);
controlPanel.doLayout();
if (expandButton != null) {
int ebpw = expandButton.getPreferredSize().width;
int ebph = expandButton.getPreferredSize().height;
int maxHeight = getBandTitleHeight() - 4;
if (ebph > maxHeight)
ebph = maxHeight;
int expandButtonBottomY = c.getHeight()
- (getBandTitleHeight() - ebph) / 2;
boolean ltr = ribbonBand.getComponentOrientation()
.isLeftToRight();
if (ltr) {
expandButton.setBounds(c.getWidth() - ins.right - ebpw,
expandButtonBottomY - ebph, ebpw, ebph);
} else {
expandButton.setBounds(ins.left,
expandButtonBottomY - ebph, ebpw, ebph);
}
}
}
}
/**
* Event listener to handle global ribbon events. Currently handles:
* <ul>
* <li>Marking a ribbon band to be hovered when the mouse moves over it.</li>
* <li>Mouse wheel events anywhere in the ribbon to rotate the selected
* task.</li>
* </ul>
*/
private static class AWTRibbonEventListener implements AWTEventListener {
private static AWTRibbonEventListener instance;
private int installCount = 0;
private AbstractRibbonBand lastHovered;
public static void install() {
if (instance == null) {
instance = new AWTRibbonEventListener();
java.security.AccessController
.doPrivileged(new java.security.PrivilegedAction<Object>() {
public Object run() {
Toolkit
.getDefaultToolkit()
.addAWTEventListener(
instance,
AWTEvent.MOUSE_EVENT_MASK
| AWTEvent.MOUSE_WHEEL_EVENT_MASK);
return null;
}
});
}
instance.installCount++;
}
public static boolean uninstall() {
if (instance != null) {
instance.installCount--;
if (instance.installCount == 0) {
// really uninstall
Toolkit.getDefaultToolkit()
.removeAWTEventListener(instance);
instance = null;
}
return true;
}
return false;
}
public void eventDispatched(AWTEvent event) {
MouseEvent mouseEvent = (MouseEvent) event;
if (mouseEvent.getID() == MouseEvent.MOUSE_ENTERED) {
Object object = event.getSource();
if (!(object instanceof Component)) {
return;
}
Component component = (Component) object;
AbstractRibbonBand band = (component instanceof AbstractRibbonBand) ? ((AbstractRibbonBand) component)
: (AbstractRibbonBand) SwingUtilities
.getAncestorOfClass(AbstractRibbonBand.class,
component);
setHoveredBand(band);
}
if (mouseEvent.getID() == MouseEvent.MOUSE_WHEEL) {
if (PopupPanelManager.defaultManager().getShownPath().size() > 0)
return;
Object object = event.getSource();
if (!(object instanceof Component)) {
return;
}
Component component = (Component) object;
// get the deepest subcomponent at the event point
MouseWheelEvent mouseWheelEvent = (MouseWheelEvent) mouseEvent;
Component deepest = SwingUtilities.getDeepestComponentAt(
component, mouseWheelEvent.getX(), mouseWheelEvent
.getY());
JRibbon ribbon = (JRibbon) SwingUtilities.getAncestorOfClass(
JRibbon.class, deepest);
if (ribbon != null) {
// if the mouse wheel scroll has happened inside a ribbon,
// ask the UI delegate to handle it
ribbon.getUI().handleMouseWheelEvent(
(MouseWheelEvent) mouseEvent);
}
}
}
private void setHoveredBand(AbstractRibbonBand band) {
if (lastHovered == band) {
return; // nothing to do as we are already over
}
if (lastHovered != null) {
// RibbonBandUI ui = lastHovered.getUI();
lastHovered.getUI().trackMouseCrossing(false);
}
lastHovered = band;
if (band != null) {
band.getUI().trackMouseCrossing(true);
}
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#update(java.awt.Graphics,
* javax.swing.JComponent)
*/
@Override
public void update(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g.create();
RenderingUtils.installDesktopHints(g2d);
super.update(g2d, c);
g2d.dispose();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#paint(java.awt.Graphics,
* javax.swing.JComponent)
*/
@Override
public void paint(Graphics g, JComponent c) {
Graphics2D graphics = (Graphics2D) g.create();
Insets ins = ribbonBand.getInsets();
this.paintBandBackground(graphics, new Rectangle(0, 0, c.getWidth(), c
.getHeight()));
if (!(ribbonBand.getCurrentResizePolicy() instanceof IconRibbonBandResizePolicy)) {
String title = ribbonBand.getTitle();
int titleHeight = getBandTitleHeight();
int bandTitleTopY = c.getHeight() - titleHeight;
this.paintBandTitleBackground(graphics, new Rectangle(0,
bandTitleTopY, c.getWidth(), titleHeight), title);
boolean ltr = ribbonBand.getComponentOrientation().isLeftToRight();
int titleWidth = c.getWidth() - 2 * ins.left - 2 * ins.right;
int titleX = 2 * ins.left;
if (expandButton != null) {
if (ltr) {
titleWidth = expandButton.getX() - 2 * ins.right - 2
* ins.left;
} else {
titleWidth = ribbonBand.getWidth() - expandButton.getX()
- expandButton.getWidth() - 2 * ins.right - 2
* ins.left;
titleX = expandButton.getX() + expandButton.getWidth() + 2
* ins.left;
}
}
this.paintBandTitle(graphics, new Rectangle(titleX, bandTitleTopY,
titleWidth, titleHeight), title);
}
graphics.dispose();
}
/**
* Paints band title pane.
*
* @param g
* Graphics context.
* @param titleRectangle
* Rectangle for the title pane.
* @param title
* Title string.
*/
protected void paintBandTitle(Graphics g, Rectangle titleRectangle,
String title) {
// fix for issue 10 - empty ribbon band
if (titleRectangle.width <= 0)
return;
Graphics2D graphics = (Graphics2D) g.create();
graphics.setFont(FlamingoUtilities.getFont(this.ribbonBand,
"Ribbon.font", "Button.font", "Panel.font"));
FontMetrics fm = graphics.getFontMetrics();
int y = titleRectangle.y - 2 + (titleRectangle.height + fm.getAscent())
/ 2;
int currLength = (int) fm.getStringBounds(title, g).getWidth();
String titleToPaint = title;
while (currLength > titleRectangle.width) {
title = title.substring(0, title.length() - 1);
titleToPaint = title + "...";
currLength = (int) fm.getStringBounds(titleToPaint, g).getWidth();
}
int x = titleRectangle.x + (titleRectangle.width - currLength) / 2;
graphics.setColor(this.ribbonBand.getForeground());
graphics.drawString(titleToPaint, x, y);
graphics.dispose();
}
/**
* Paints band title pane.
*
* @param g
* Graphics context.
* @param titleRectangle
* Rectangle for the title pane.
* @param title
* Title string.
*/
protected void paintBandTitleBackground(Graphics g,
Rectangle titleRectangle, String title) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver
.derive(0.7f + 0.3f * this.rolloverAmount));
FlamingoUtilities.renderSurface(g2d, this.ribbonBand, titleRectangle,
this.rolloverAmount > 0.0f, true, false);
g2d.dispose();
}
public void setRolloverAmount(float rolloverAmount) {
this.rolloverAmount = rolloverAmount;
}
/**
* Paints band background.
*
* @param graphics
* Graphics context.
* @param toFill
* Rectangle for the background.
*/
protected void paintBandBackground(Graphics graphics, Rectangle toFill) {
graphics.setColor(ribbonBand.getBackground());
graphics.fillRect(toFill.x, toFill.y, toFill.width, toFill.height);
}
@Override
public float getRolloverAmount() {
return this.rolloverAmount;
}
/**
* Returns the height of the ribbon band title area.
*
* @return The height of the ribbon band title area.
*/
@Override
public int getBandTitleHeight() {
Font font = FlamingoUtilities.getFont(this.ribbonBand, "Ribbon.font",
"Button.font", "Panel.font");
if (font == null) {
// Nimbus - is that you?
font = new JLabel().getFont();
}
int result = font.getSize() + 5;
if (result % 2 == 0)
result++;
return result;
}
/**
* Round border for the ribbon bands.
*
* @author Kirill Grouchnikov
*/
protected static class RoundBorder implements Border {
/**
* Border color.
*/
protected Color color;
/**
* Border insets.
*/
protected Insets insets;
/**
* Creates the new border.
*
* @param color
* Border color.
* @param insets
* Border insets.
*/
public RoundBorder(Color color, Insets insets) {
this.color = color;
this.insets = insets;
}
@Override
public Insets getBorderInsets(Component c) {
return this.insets;
}
@Override
public boolean isBorderOpaque() {
return false;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y,
int width, int height) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(this.color);
g2d.drawRoundRect(x, y, width - 1, height - 1, 3, 3);
g2d.dispose();
}
}
@Override
public int getPreferredCollapsedWidth() {
return this.collapsedButton.getPreferredSize().width + 2;
}
@Override
public void trackMouseCrossing(boolean isMouseIn) {
if (isMouseIn) {
this.rolloverTimeline.play();
} else {
this.rolloverTimeline.playReverse();
}
this.ribbonBand.repaint();
}
/**
* This method is for unit tests only and should not be called by the
* application code.
*
* @return The expand button of the matching ribbon band.
*/
public AbstractCommandButton getExpandButton() {
return this.expandButton;
}
}